This example mirrors cifti.4D.html.
In [1]:
from pathlib import Path
from ipyniivue import download_dataset
BASE_API_URL = "https://niivue.com/demos/images/"
DATA_FOLDER = Path("images")
# Download data for example
download_dataset(
BASE_API_URL,
DATA_FOLDER,
files=[
"Conte69.MyelinAndCorrThickness.32k_fs_LR.dtseries.nii",
"Conte69.L.inflated.32k_fs_LR.surf.gii",
],
)
Downloading Conte69.MyelinAndCorrThickness.32k_fs_LR.dtseries.nii... Downloading Conte69.L.inflated.32k_fs_LR.surf.gii... Dataset downloaded successfully to images.
In [2]:
import math
import ipywidgets as widgets
import ipyniivue
# Initialize NiiVue widget
v = ipyniivue.NiiVue()
v.opts.show_3d_crosshair = True
v.opts.back_color = [0.9, 0.9, 1, 1]
v.set_slice_type(ipyniivue.SliceType.RENDER)
# Define Mesh and Layers
mesh_layer_config = {
"path": DATA_FOLDER / "Conte69.MyelinAndCorrThickness.32k_fs_LR.dtseries.nii",
"cal_min": 0.01,
"cal_max": 3.5,
"colormap": "rocket",
"opacity": 0.7,
}
mesh_config = {
"path": DATA_FOLDER / "Conte69.L.inflated.32k_fs_LR.surf.gii",
"rgba255": [255, 255, 255, 255],
"layers": [mesh_layer_config],
}
# Load the mesh
v.load_meshes([mesh_config])
# Set Clip Plane
v.set_clip_plane(-0.1, 270, 0)
# --- UI Controls ---
# Timepoint Slider
timepoint_slider = widgets.IntSlider(
value=0, min=0, max=1, description="Timepoint:", continuous_update=True
)
def on_timepoint_change(change):
"""Handle timepoint change."""
if v.meshes and v.meshes[0].layers:
v.meshes[0].layers[0].frame_4d = change["new"]
timepoint_slider.observe(on_timepoint_change, names="value")
# Opacity Slider
opacity_slider = widgets.FloatSlider(
value=0.7,
min=0.1,
max=1.0,
step=0.1,
description="Opacity:",
continuous_update=True,
)
def on_opacity_change(change):
"""Handle opacity change."""
if v.meshes and v.meshes[0].layers:
v.meshes[0].layers[0].opacity = change["new"]
opacity_slider.observe(on_opacity_change, names="value")
# Shader Buttons
shader_names = v.mesh_shader_names()
def create_shader_button(name):
"""Create a shader button."""
btn = widgets.Button(description=name)
def on_click(b):
if v.meshes:
v.set_mesh_shader(v.meshes[0].id, name)
btn.on_click(on_click)
return btn
shader_buttons = [create_shader_button(name) for name in shader_names]
# Organize shader buttons in a grid
num_cols = 6
num_rows = math.ceil(len(shader_buttons) / num_cols)
shader_grid = []
for i in range(num_rows):
row_buttons = shader_buttons[i * num_cols : (i + 1) * num_cols]
shader_grid.append(widgets.HBox(row_buttons))
shader_buttons_widget = widgets.VBox(shader_grid)
# Display Layout
controls_header = widgets.HBox([timepoint_slider, opacity_slider])
display(
widgets.VBox([controls_header, v, widgets.Label("Shaders:"), shader_buttons_widget])
)